package org.dmcs.homework.statistics.implementations;

import java.util.Arrays;

import org.dmcs.homework.statistics.api.IMeanCalculator;

import Jama.Matrix;

/**
 * Calculates the averages on a given data set.
 * @author Zielony
 * @version 1.0
 */
public class MeanCalculator implements IMeanCalculator {
	/**
	 * {@inheritDoc}
	 */
	public double[] calculateMeanVector(Matrix data, int[] classIndices) {
		/*
		 * Jesli nie podano zbioru obiektów należacych do klasy (jako tablicy indeksów ich kolumn), wyjatek.
		 */
		if(classIndices == null || classIndices.length == 0) {
			throw new IllegalArgumentException("MeanCalculator|calculateMeanVector|classIndices array is null or empty");
		}
		
		/*
		 * Jesli nie podano zbioru danych, na których operujemy, wyjatek.  
		 */
		if(data == null) {
			throw new IllegalArgumentException("MeanCalculator|calculateMeanVector|data Matrix is null");
		}
		else if(data.getColumnDimension() == 0) {
			throw new IllegalArgumentException("MeanCalculator|calculateMeanVector|data Matrix has no columns");
		}
		else if(data.getRowDimension() == 0) {
			throw new IllegalArgumentException("MeanCalculator|calculateMeanVector|data Matrix has no rows");
		}
		
		/*
		 * Sprawdzenie calkowitej ilosci dostpnych cech.
		 */
		int featureCount = data.getRowDimension();
		
		/*
		 * Inicjalizacja wektora sredniej zerami.
		 */
		double[] meanVector = new double[featureCount];
		Arrays.fill(meanVector, 0.0);
		
		/*
		 * Pojedynczy obiekt z danej klasy.
		 */
		double[] iObject;
		
		for(int i=0;i<classIndices.length;i++) {
			/*
			 * Pobranie i-tego obiektu danej klasy.
			 */
			iObject = data.getColumnVector(classIndices[i]);
			
			/*
			 * Obliczanie sredniej wartosci dla kazdej cechy osobno.
			 */
			for(int j=0; j<iObject.length; j++){
				meanVector[j] += (iObject[j]/classIndices.length);
			}
		}
		
		return meanVector;
	}

	/**
	 * {@inheritDoc}
	 */
	public double[] calculateMeanVector(Matrix data) {
		/*
		 * Tablica zawierajca indeksy wszystkich obiektów.
		 */
		int[] allIndices = new int[data.getColumnDimension()];
 		
		/*
		 * Uzupelnianie tablicy wszystkimi indeksami.
		 */
		for(int i=0;i<data.getColumnDimension();i++) {
			allIndices[i] = i;
		}
		
		/*
		 * Odwolanie do funkcji obliczajacej wektor srednich dla konkretnych indeksów.
		 */
		return calculateMeanVector(data, allIndices);
	}
	
	/**
	 * {@inheritDoc}
	 */
	public Matrix calculateExtendedMeanMatrix(Matrix data, int[] classIndices) {
		/*
		 * Obliczanie wektora srednich cech dla danej klasy.
		 */
		double[] meanVector = calculateMeanVector(data, classIndices);
		
		/*
		 * Budowa macierzy w oparciu o ten wektor.
		 */
		Matrix meanMatrix = new Matrix(meanVector, meanVector.length);		
		
		return meanMatrix;
	}
	
	public double[] calculateMeanVector(Matrix data, int[] classIndices,
			int[] featureSet) {
		
		//KLUDGE: Tak naprawde powinno to byc robione inaczej: najpierw eliminacja,
		// a potem obliczenia - mniejsza zlozonosc czasowa i pamieciowa. Poprawic i 
		// uzgodnic wyzszy poziom ze zmianami.
		
		double[] fullMeanVector = calculateMeanVector(data, classIndices);
		
		double[] finalMeanVector = new double[featureSet.length];
		
		for(int i=0;i<featureSet.length; i++) {
			finalMeanVector[i] = fullMeanVector[featureSet[i]];
		}
		
		return finalMeanVector;
	}
}